<template>
  <!-- 当smallarr有数组项时，才显示数组，否则显示loading效果 -->
  <div>
    <slot v-show="smallarr.length>0" :smallarr="smallarr"></slot>
    <p style="text-align: center;line-height: 2;"><i v-show="!isBottom" class="iconfont icon-loading"></i> {{isBottom ? '已经到底了~' : 'loading...'}}</p>
  </div>
</template>
 
<script>
// 定义一个定时器名称，用来存储与销毁定时器
let timer = null;
// smallarr代表处理过的数组,bigarr代表传入进来的数组
export default {
  data() {
    return {
      // 代表处理过的数组，真正传给外部组件的数组
      smallarr: [],
      // 滚动到第几页(也可表示第几次滚动)
      pageIndex: 0,
      // 是否已经到底了，如果是，则为true，默认false
      isBottom: false
    }
  },
  // 将你要渲染的数组直接传入进来
  //   props: ["bigarr", "size"],
  props: {
    bigarr: {
      type: Array,
      default: []
    },
    size: {
      type: Number,
      default: 0
    }
  },
  watch: {
    "bigarr": {
      handler(n, o) {
        this.pageIndex = 0;
        // 监听到数组的新值长度大于0，则调用处理数组的方法
        if (n.length > 0) {
          this.isBottom = false;
          this.sliceArr();
        }else{
          this.isBottom = true;
          this.smallarr = [];
        }
      },
      deep: true
    }
  },
  mounted() {
    // 监听滚动
    window.addEventListener("scroll", this.handleScroll)
  },
  destroyed() {
    // 组件一旦销毁，直接取消监听
    window.removeEventListener("scroll", this.handleScroll)
  },
  methods: {
    // 处理数组的方法
    sliceArr() {
      let _this = this;
      // 按照传过来的一页显示多少个，来决定smallarr有多少项(切割数组)
      if (this.size * (this.pageIndex+1) <= this.bigarr.length) {
        // 此处不用splice是因为splice会修改原数组bigarr，这样又会触发一次监听，因此用slice
        let myarr = this.bigarr.slice(this.smallarr.length, this.smallarr.length+this.size);
        // this.smallarr = this.smallarr.concat(myarr);   // 直接合并得到的数组 - 无效
        myarr.map(item => {
          // 因为vue无法检测复杂数据类型的新数据，因此要用$set来更新数组的每一项
          _this.$set(_this.smallarr, _this.smallarr.length, item);
        })
      } else {
        this.smallarr = this.bigarr;
        this.isBottom = true;   // 显示已经到底了~
      }
    },
    // 鼠标滚动事件
    handleScroll() {
      let _this = this;
      if (timer) {
        clearTimeout(timer);
      }

      timer = setTimeout(() => {
        //获取滚动时的高度
        let st = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
        // 浏览器窗口（文档）的可视高度(windowHeight)：（就是你肉眼可见的那部分全屏高度）
        let windowHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
        // 文档的真实高度(scrollHeight)：
        let scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
        /* 这里提示：当 windowHeight + st >= scrollHeight  时就表示滚到底了。 */
        if (windowHeight + st >= scrollHeight) {
          clearTimeout(timer);    // 触底就直接清除定时器
          timer = null;           // 重新让定时器归null
          // Math.ceil向上取整一个结果：调用者传入的数组的长度除以一次显示多少份的结果
          if (this.pageIndex >= Math.ceil(this.bigarr.length / this.size)) {
            // 代表已经翻到最后一页，直接显示已经到底了～
            this.isBottom = true;
            // 取消监听滚动事件
            window.removeEventListener("scroll", this.handleScroll)
            return;  // 阻断后续所有操作
          }

          // 能运行到这里，证明还没有到底部
          this.pageIndex++;        // 代表翻页了
          this.sliceArr();          // 触底需要加载后续的项,调用处理数组的方法
        }
      }, 1000)
    }
  }
}
</script>
 
<style lang = "less" scoped>
@import "https://at.alicdn.com/t/font_2730880_ylrio3ahhx.css";

.icon-loading{
  display: inline-block;
  vertical-align: middle;
  animation: round 1s linear infinite;
}

@keyframes round {
  from {transform: rotate(0);}
  to{transform: rotate(360deg);}
}
</style>